package net.ncraft.mc.ezframework.core.handler.command;

import net.ncraft.mc.ezframework.core.SpigotEzFrameworkCore;
import net.ncraft.mc.ezframework.core.annotations.command.CommandMethod;
import net.ncraft.mc.ezframework.core.annotations.command.CommandOption;
import net.ncraft.mc.ezframework.core.annotations.command.CommandTab;
import net.ncraft.mc.ezframework.core.annotations.command.ECommand;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.plugin.java.JavaPlugin;
import org.reflections.Reflections;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CommandHandler {

    private static final List<Class<?>> COMMAND_CLASSES = new ArrayList<>();

    public static void load(JavaPlugin plugin) {
        Reflections reflections = new Reflections(plugin.getClass().getPackageName());
        COMMAND_CLASSES.addAll(reflections.getTypesAnnotatedWith(ECommand.class));
        registerCommands();
    }

    private static void registerCommands() {
        for (Class<?> commandClass : COMMAND_CLASSES) {

            ECommand ECommand = commandClass.getAnnotation(ECommand.class);

            TabExecutor command = new TabExecutor() {
                @Override
                public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {

                    for (Method method : commandClass.getMethods()) {

                        if (!method.isAnnotationPresent(CommandMethod.class)) {
                            continue;
                        }

                        String commandSign = method.getAnnotation(CommandMethod.class).sign();
                        String[] commandSignArgs = commandSign.split(" ");
                        Field[] optionField = commandClass.getDeclaredFields();

                        //检测是否是有效指令
                        boolean isCommand = false;
                        for (Field field : optionField) {
                            CommandOption cmdOptionAnn = field.getAnnotation(CommandOption.class);

                            if (cmdOptionAnn == null) {
                                continue;
                            }

                            int index = cmdOptionAnn.index();

                            if (index > args.length) {
                                continue;
                            }

                            for (int i = 0; i < args.length; i++) {
                                if (index == i) {
                                    if (Arrays.stream(cmdOptionAnn.values()).toList().contains(args[i])) {
                                        isCommand = true;
                                        break;
                                    }
                                }

                            }
                        }
                        //如果是无效指令 则执行{any}方法
                        if (!isCommand) {
                            if (commandSign.equalsIgnoreCase("{any}")) {
                                try {
                                    method.invoke(commandClass.newInstance(), sender, args);
                                    return true;
                                } catch (IllegalAccessException | InvocationTargetException |
                                         InstantiationException e) {
                                    throw new RuntimeException(e);
                                }
                            }
                        }


                        if (args.length == commandSignArgs.length - 1) {
                            if (commandSignArgs[commandSignArgs.length - 1].equalsIgnoreCase("{arg}")) {

                                boolean thisMethod = false;
                                for (int i = 0; i < args.length; i++) {
                                    String arg = args[i];
                                    for (int j = 0; j < commandSignArgs.length - 1; j++) {
                                        if (i == j) {
                                            if (arg.equalsIgnoreCase(commandSignArgs[j])) {
                                                thisMethod = true;
                                            } else {
                                                thisMethod = false;
                                                break;
                                            }
                                        }
                                    }
                                }

                                if (thisMethod) {
                                    try {
                                        method.invoke(commandClass.newInstance(), sender, args);
                                        return true;
                                    } catch (IllegalAccessException | InvocationTargetException |
                                             InstantiationException e) {
                                        throw new RuntimeException(e);
                                    }
                                }
                            }
                        }


                        //上面是特殊情况
                        //正常匹配命令签名..........................
                        if (commandSignArgs.length != args.length) {
                            continue;
                        }

                        StringBuilder builder1 = new StringBuilder();
                        StringBuilder builder2 = new StringBuilder();

                        for (int i = 0; i < commandSignArgs.length; i++) {
                            commandSignArgs[i] = commandSignArgs[i].replace("{arg}", args[i]);
                        }

                        for (String commandSignArg : commandSignArgs) {
                            builder1.append(commandSignArg).append(" ");
                        }

                        List<String> argsList = Arrays.stream(args).toList();
                        for (int i = 0; i < argsList.size(); i++) {
                            builder2.append(argsList.get(i)).append(" ");
                        }

                        if (builder1.toString().equalsIgnoreCase(builder2.toString())) {
                            try {
                                Object o = commandClass.newInstance();
                                method.invoke(o, sender, args);
                                return true;
                            } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
                                throw new RuntimeException(e);
                            }
                        }
                    }
                    return false;
                }

                @Override
                public List<String> onTabComplete(CommandSender sender, Command cmd, String label, String[] args) {

                    Field[] fields = commandClass.getDeclaredFields();
                    for (Field field : fields) {
                        if (field.isAnnotationPresent(CommandOption.class)) {
                            CommandOption commandOption = field.getAnnotation(CommandOption.class);
                            String[] tabs = commandOption.values();
                            if (args.length == commandOption.index() + 1) {
                                if (args.length > 1) {

                                    String lastArg = commandOption.lastArg();

                                    String[] lastArgs = lastArg.split(" ");

                                    StringBuilder builder1 = new StringBuilder();
                                    StringBuilder builder2 = new StringBuilder();

                                    for (int i = 0; i < lastArgs.length; i++) {
                                        lastArgs[i] = lastArgs[i].replace("{arg}", args[i]);
                                    }

                                    for (String commandSignArg : lastArgs) {
                                        builder1.append(commandSignArg);
                                    }

                                    List<String> argsList = Arrays.stream(args).toList();
                                    for (int i = 0; i < argsList.size(); i++) {
                                        builder2.append(argsList.get(i));
                                    }


                                    if (builder1.toString().equalsIgnoreCase(builder2.toString())) {

                                        if (Arrays.stream(tabs).toList().contains("{tab}")) {
                                            if (args.length == lastArgs.length+1) {
                                                Method[] methods =  commandClass.getMethods();
                                                for (Method method : methods) {
                                                    if (!method.isAnnotationPresent(CommandTab.class)) {
                                                        continue;
                                                    }
                                                    CommandTab tabAnn = method.getAnnotation(CommandTab.class);
                                                    String tabSign = tabAnn.sign();
                                                    String[] tabArgs = tabSign.split(" ");

                                                    for (int i = 0; i < tabArgs.length; i++) {
                                                        tabArgs[i] = tabArgs[i].replace("{arg}", args[i]);
                                                    }
                                                    StringBuilder builder3 = new StringBuilder();

                                                    for (String tabArg : tabArgs) {
                                                        builder3.append(tabArg);
                                                    }

                                                    if (builder3.toString().equalsIgnoreCase(builder2.toString())) {
                                                        try {
                                                            Object o = commandClass.newInstance();
                                                            return (List<String>) method.invoke(o, sender, args);
                                                        } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
                                                            throw new RuntimeException(e);
                                                        }
                                                    }

                                                }
                                            }
                                        }


                                        return Arrays.stream(tabs).filter(s -> s.startsWith(args[args.length - 1])).toList();
                                    } else {
                                       continue;
                                    }
                                }
                                return Arrays.stream(tabs).filter(s -> s.startsWith(args[args.length - 1])).toList();
                            }
                        }
                    }
                    return List.of();
                }
            };

            SpigotEzFrameworkCore.getPlugin().getCommand(ECommand.name()).setExecutor(command);
        }
    }

}
